<!DOCTYPE html>



  


<html class="theme-next pisces use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="Hexo, NexT" />










<meta name="description" content="深入理解Java虚拟机(jvm性能调优+内存模型+虚拟机原理)  @Author:songxiankun2008@126.com  1. jdk 、jre 、jvm的关系 == JDK &amp;gt; JRE &amp;gt; JVM == Java Development Kit  &amp;gt; Java Runtime Environment  &amp;gt;  Java Virtual Machine (根据这个">
<meta property="og:type" content="article">
<meta property="og:title" content="深入理解Java虚拟机">
<meta property="og:url" content="http://smallkk.gitee.io/2018/03/24/深入理解Java虚拟机/index.html">
<meta property="og:site_name" content="Hi , 小坤坤">
<meta property="og:description" content="深入理解Java虚拟机(jvm性能调优+内存模型+虚拟机原理)  @Author:songxiankun2008@126.com  1. jdk 、jre 、jvm的关系 == JDK &amp;gt; JRE &amp;gt; JVM == Java Development Kit  &amp;gt; Java Runtime Environment  &amp;gt;  Java Virtual Machine (根据这个">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="https://sxk.s3.didiyunapi.com/pic/jvm/1.png">
<meta property="og:image" content="https://sxk.s3.didiyunapi.com/pic/jvm/2.png">
<meta property="og:image" content="https://sxk.s3.didiyunapi.com/pic/jvm/3.jpg">
<meta property="og:image" content="https://sxk.s3.didiyunapi.com/pic/jvm/4.jpg">
<meta property="og:image" content="https://sxk.s3.didiyunapi.com/pic/jvm/5.jpg">
<meta property="og:image" content="https://sxk.s3.didiyunapi.com/pic/jvm/6.jpg">
<meta property="og:updated_time" content="2018-04-30T19:12:35.429Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="深入理解Java虚拟机">
<meta name="twitter:description" content="深入理解Java虚拟机(jvm性能调优+内存模型+虚拟机原理)  @Author:songxiankun2008@126.com  1. jdk 、jre 、jvm的关系 == JDK &amp;gt; JRE &amp;gt; JVM == Java Development Kit  &amp;gt; Java Runtime Environment  &amp;gt;  Java Virtual Machine (根据这个">
<meta name="twitter:image" content="https://sxk.s3.didiyunapi.com/pic/jvm/1.png">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Pisces',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://smallkk.gitee.io/2018/03/24/深入理解Java虚拟机/"/>





  <title>深入理解Java虚拟机 | Hi , 小坤坤</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">Hi , 小坤坤</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://smallkk.gitee.io/2018/03/24/深入理解Java虚拟机/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="S-Name Small·kk">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Hi , 小坤坤">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">深入理解Java虚拟机</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-03-24T08:57:12+08:00">
                2018-03-24
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <blockquote>
<h2 id="深入理解Java虚拟机-jvm性能调优-内存模型-虚拟机原理"><a href="#深入理解Java虚拟机-jvm性能调优-内存模型-虚拟机原理" class="headerlink" title="深入理解Java虚拟机(jvm性能调优+内存模型+虚拟机原理)"></a><strong>深入理解Java虚拟机(jvm性能调优+内存模型+虚拟机原理)</strong></h2></blockquote>
<blockquote>
<p>@Author:<a href="mailto:songxiankun2008@126.com" target="_blank" rel="noopener">songxiankun2008@126.com</a></p>
</blockquote>
<h5 id="1-jdk-、jre-、jvm的关系"><a href="#1-jdk-、jre-、jvm的关系" class="headerlink" title="1. jdk 、jre 、jvm的关系"></a>1. jdk 、jre 、jvm的关系</h5><hr>
<p>== JDK &gt; JRE &gt; JVM ==</p>
<p>Java Development Kit  &gt; Java Runtime Environment  &gt;  Java Virtual Machine</p>
<p>(根据这个层级目录关系，无论安装JDK还是JRE,JVM都会随之安装的)</p>
<p>代码开发是在JDK，运行是在JRE，执行时的字节码在JVM</p>
<p>RIA:富客户端应用程序</p>
<p><img src="https://sxk.s3.didiyunapi.com/pic/jvm/1.png" alt="image"></p>
<h5 id="2-内存溢出问题的分析与解决"><a href="#2-内存溢出问题的分析与解决" class="headerlink" title="2. 内存溢出问题的分析与解决"></a>2. 内存溢出问题的分析与解决</h5><hr>
<p>VM arguments (添加Java虚拟机运行时的参数):</p>
<pre><code>-XX:+HeapDumpOnOutOfMemoryError
// 制定一个快照,堆内存出错,内存溢出等报错的时候
//快照会存放在项目里面后缀名为.hprof的文件

-XX:+HeapDumpOnOutOfMemoryError -Xms20m -Xmx20m
// 制定溢出内存的大小;超过就报错,停止执行并释放内存
</code></pre><p>hprof这个内存快照文件需要专门的工具打开：Eclipse Memory Analyzer(基于Eclipse内核),导入文件后可以看到快照的信息：图谱和错误分布</p>
<h5 id="3-jvm可视化监控工具"><a href="#3-jvm可视化监控工具" class="headerlink" title="3. jvm可视化监控工具"></a>3. jvm可视化监控工具</h5><hr>
<p>jdk安装目录下：</p>
<pre><code>\bin\jconsole.exe
</code></pre><p>如果配置Path变量路径的话直接</p>
<pre><code>cmd:jconsole
</code></pre><p>在cmd里面的<code>jps</code>命令是可以列出所有的java进程</p>
<p>在jconsole.exe里面堆内存图像曲线解释：类似心电图一上一下;问：为什么不是一直都在上? 答：上升是在耗费内存的使用,下降是垃圾回收机制及时的回收了垃圾</p>
<p>在内存池的”PS Eden Space”(Eden区)是GC经常光顾的地方,所以用可视化工具查看内存变化的区域就是多看这个Eden区域</p>
<p>堆内存分为：</p>
<pre><code>① 新生代内存 ② 老年代内存
</code></pre><p>堆内存又分为3个板块： </p>
<pre><code>① Eden(占2/4) ② Survivor(占1/4) ③ Survivor(占1/4)
</code></pre><p>刚刚new出来的一个对象首先是扔到Eden区域,GC会随时将这里面是垃圾的回收走,如果没有被回收到的就是存活下来的,就会进入Survivor(存活区)内存块里面;如果长期存活下来就会进入”老年代”内存区域.</p>
<h6 id="4-Java的发展历史"><a href="#4-Java的发展历史" class="headerlink" title="4. Java的发展历史"></a>4. Java的发展历史</h6><hr>
<ol>
<li><p>1995年5月 Oak语言 ==》 Java 1.0 (理念：write once and run anywhere 一次写下 到处运行)</p>
</li>
<li><p>1996年1月 jdk 1.0 发布; jvm在jdk之中,这是第一个jvm,是sun公司的Classic VM</p>
</li>
<li><p>1996年9月 首届 JavaOne 大会</p>
</li>
<li><p>1997年2月 jdk 1.1  发布;(内部类,反射,JDBC,JavaBeans,rmi,jar文件格式)</p>
</li>
<li><p>1998年    jdk 1.2 发布 此时Java就有了三个方向(J2SE J2EE J2ME),与此同时swing也加入了进去,并且内置了jit,改进了HotSpot VM</p>
</li>
<li><p>2000年5月 jdk 1.3 新增Timer 改进java2D;从此开始java进入了一个高速发展期,并规定每两年就发布一个java的主版本</p>
</li>
<li><p>2002年2月 jdk 1.4 发布,是一个里程碑的版本,非常核心,是Java走向成熟的版本;这个时候问世了==Struts,Hibernate,Spring1.x==,Spring1.X全都是基于”配置”执行,在jdk1.4上可以直接运行;与此新增 正则表达式,Nio,日志,Xml解析器</p>
</li>
<li><p>2004年9月 jdk 1.5 发布,别名:Tiger,内容:自动装箱拆箱、泛型、注解、枚举、变长参数、增强for循环;(因为有注解可以用了,所以Spring2.X摒弃了1.X的各种配置,开始使用jdk1.5的注解)</p>
</li>
<li><p>2006年 jdk 1.6  更名：将98年1.2版本的==J2SE-&gt;JavaSE、J2EE-&gt;JavaEE、J2ME-&gt;JavaME; jdk1.6 -&gt; JDK6.0== ;新特性:提供脚本语言的支持(动态语言)、提供了一些编译APi、一些微型服务http的APi</p>
<p>2006年11月13日Java大会宣布将所有的JDK什么东西的全部开源(耗费大量的人力财力,没有赶上两年一个jdk主版本的速度,所以下一个主版本的发布就在2009年)</p>
</li>
<li><p>2009年发布 jdk 1.7 (规划了 Lambda(动态语言/函数式编程),Jigsaw(模块化),但是大多数的模块化都是用的OSGI)</p>
<p>同年(2009)Oracle公司以74亿美元收购了SUN公司</p>
<p>从2009年开始发布jdk7的第一个版本,到2011年发布了JDK7的最终版本</p>
</li>
<li><p>2014年3月 JDK1.8发布</p>
</li>
</ol>
<h6 id="5-Java技术体系"><a href="#5-Java技术体系" class="headerlink" title="5. Java技术体系"></a>5. Java技术体系</h6><hr>
<p>  ①</p>
<ul>
<li>Java程序设计语言</li>
<li>各硬件平台上的Java虚拟机</li>
<li>Class文件格式</li>
<li>Java APi</li>
<li><p>第三方的Java类库</p>
<p>②</p>
</li>
<li>JavaSE   Java Standard edition 标准版</li>
<li>JavaEE   Java企业级开发：共有13种技术体系</li>
<li>JavaME   nokia s60 java</li>
</ul>
<h5 id="6-Java8新特性"><a href="#6-Java8新特性" class="headerlink" title="6. Java8新特性"></a>6. Java8新特性</h5><hr>
<ul>
<li><p>接口的默认方法和静态方法</p>
<ul>
<li>(Java8使用两个新概念扩展了接口的含义：默认方法和静态方法。默认方法是的开发者可以在不破坏二进制兼容性的前提下，往现存接口中添加新的方法，即不强制那些实现了该接口的类也同事实现这个新加的方法。)</li>
</ul>
</li>
<li><p>Lambda 表达式和函数式编程</p>
</li>
<li>Date APi</li>
<li><p>更好的类型推断</p>
<ul>
<li>(Java8编译器在类型推断方面有很大的提升，在很多场景下编译器可以推导出某个参数的数据类型，从而使得代码更为简洁)</li>
</ul>
</li>
<li><p>Nashorn JavaScript引擎</p>
<ul>
<li>(使用Metaspace（JEP 122）代替持久代（PermGen space）。在JVM参数方面，使用-XX:MetaSpaceSize和-XX：MaxMetaspaceSize代替原来的-XX:PermSize和-XX:MaxPermSize)</li>
</ul>
</li>
</ul>
<h5 id="7-lanmbda表达式简介"><a href="#7-lanmbda表达式简介" class="headerlink" title="7. lanmbda表达式简介"></a>7. lanmbda表达式简介</h5><hr>
<p>不使用Lanmbda:</p>
<pre><code>jButton.addActionListener(new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent e){
        System.out.println(&quot;Hello&quot;);
    }
})
</code></pre><p>使用Lanmbda表达式：</p>
<pre><code>jButton.addActionListener(event -&gt; System.out.println(&quot;Hello&quot;));
</code></pre><h5 id="8-Java虚拟机"><a href="#8-Java虚拟机" class="headerlink" title="8. Java虚拟机"></a>8. Java虚拟机</h5><hr>
<ul>
<li><ol>
<li>classic vm</li>
</ol>
<ul>
<li>96年发布的虚拟机</li>
<li>世界上第一款商用的Java虚拟机</li>
<li>只能使用纯解释器的方式来执行Java代码</li>
</ul>
</li>
<li><ol start="2">
<li>Exact VM</li>
</ol>
<ul>
<li>Exact Memory Management 准确试内存管理</li>
<li>编译器和解释器混合工作以及两级即时编译器</li>
<li>只在Solaris平台发布<ul>
<li>(还没得Windows和Linux)</li>
</ul>
</li>
<li>英雄气短<ul>
<li>(jdk1.2后就没怎么用Exact VM了,反而还是classic vm,到了JDK1.3后换成了其他的)</li>
</ul>
</li>
</ul>
</li>
<li><ol start="3">
<li>==HotSpot VM==</li>
</ol>
<ul>
<li>HotSpot的历史<ul>
<li>HotSpot VM不是sun公司的,但是HotSpot VM继承sun公司前两款商用虚拟机的优点,于是sun公司就收购了HotSpot VM</li>
</ul>
</li>
<li>优势</li>
<li>称霸武林<ul>
<li>2006年宣布开源后,从2007年开始 sun公司下的两个不同的JDK的虚拟机全部都是HotSpot VM；从2007-至今都是这个虚拟机</li>
</ul>
</li>
</ul>
</li>
<li><ol start="4">
<li>KVM<ul>
<li>Kilobyte 简单、轻量、高度可移植</li>
<li>在手机平台运行(eg:noika s60 但是运行速度很慢)</li>
</ul>
</li>
</ol>
</li>
<li><ol start="5">
<li>JRockit<ul>
<li>BEA</li>
<li>世界上最快的Java虚拟机</li>
<li>专注于服务器端应用</li>
<li>优势<ul>
<li>垃圾收集器</li>
<li>MissionControl服务套件</li>
</ul>
</li>
</ul>
</li>
</ol>
</li>
<li><p>[ ]     BEA JRockit Mission Control,用来诊断泄露并指出根本原因。该工具的开销非常小，因此可以使用它来寻找生产环境中的系统的内存泄露。</p>
</li>
<li><p>[x]     BEA JRockit Mission Control (JRMC)于2005年12月面世，并从JRockit R26.0.0版本开始捆绑了这个工具套件，目前最新的版本是2.0.1.它是一组以极低的开销来监控、管理和分析生产环境中的应用程序的工具。它包括三个独立的应用程序：内存泄露检测器(Memory Leak Detector)、JVM运行时分析器(RunTime Analyzer)和管理控制台(Management Console)。</p>
</li>
<li><ol start="6">
<li>J9<ul>
<li>IBM公司出产,不是sun</li>
<li>原名为 Technology for Java Virtual Machine 简称：IT4J;但是为了方便阅读就取名为 J9</li>
<li>类似于HotSpot</li>
<li>从服务器端到桌面应用到嵌入</li>
</ul>
</li>
</ol>
</li>
<li><ol start="7">
<li>Dalvik<ul>
<li>谷歌的</li>
<li>安卓操作系统的重要组成部分</li>
<li>dex ( dalvik Executalbe )</li>
</ul>
</li>
</ol>
</li>
<li><ol start="8">
<li>Microsoft JVM<ul>
<li>在Java诞生初期,windows还是Java的铁杆粉丝,windows为了Java能在win下运行于是就有了这款Java虚拟机;这个虚拟机只能在windows环境下运行而且速度非常快!SUN公司不满意起诉Windows公司侵权以胜利告终;从此windows退出了JVM的研发。</li>
</ul>
</li>
</ol>
</li>
<li><ol start="9">
<li>Azul VM &amp; Liquid VM<ul>
<li>高性能的Java虚拟机</li>
<li>运行在该公司专有的硬件环境上超级炒鸡快</li>
<li>Liquid VM不需要操作系统的支持,因为它本身就是一个微型操作系统</li>
<li>平常说Java运行慢是因为程序执行会进入JVM，jvm再去调用操作系统，过程很长所以就慢；就完全体现出Liquid VM不要操作系统的优势;</li>
</ul>
</li>
</ol>
</li>
<li><ol start="10">
<li>Taobao VM<ul>
<li>淘宝根据Hotspot开发的国产的虚拟机</li>
<li>运行在 阿里 的服务器上性能非常高,但是自己拿过来用可能就达不到那样的效果</li>
<li>在GC的优化上非常高</li>
</ul>
</li>
</ol>
</li>
</ul>
<h5 id="9-内存区域"><a href="#9-内存区域" class="headerlink" title="9. 内存区域"></a>9. 内存区域</h5><hr>
<ol>
<li><p>运行时数据区里面包括”线程共享区”和”线程独占区”;</p>
</li>
<li><p>线程共享区里面又包括”方法区”和”Java堆”</p>
</li>
<li><p>线程独占区里面又包括”虚拟机栈”、”本地方法栈”和”程序计数器”</p>
</li>
<li><p>方法区：存储运行时常量池、已经虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据</p>
</li>
</ol>
<p>运行时数据区</p>
<ul>
<li><p><img src="https://sxk.s3.didiyunapi.com/pic/jvm/2.png" alt="image"></p>
</li>
</ul>
<p>++1. Java堆：存储对象实例++</p>
<p>++2. 虚拟机栈：存放方法运行时所需的数据，成为栈帧++</p>
<p>++3. 本地方法栈：为JVM所调用到的Nativa即本地方法服务++</p>
<p>++4. 程序计数器： 记录当前线程所执行到的字节码的行号++</p>
<ul>
<li><ol>
<li>程序计数器<ul>
<li><ol>
<li>程序计数器是一块较小的内存空间，它可以看做是当前线程所执行的字节码的行号指示器</li>
</ol>
</li>
<li><ol start="2">
<li>程序计数器处于线程独占区</li>
</ol>
</li>
<li><ol start="3">
<li>如果线程执行的是Java方法，这个计数器记录的是正在执行的虚拟机字节码指令的地址。如果正在执行的是Native方法，这个计数器的值为undefined</li>
</ol>
</li>
<li><ol start="4">
<li>此区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域</li>
</ol>
</li>
<li><ol start="5">
<li>goto ,Java中的goto就是跳转到哪一行去执行;但是goto是保留字关键字,JDK官方没有用,开发者也不能用;即当前JDK版本不能用goto,那么可能JDK之后的版本才会允许使用goto或者赋予其他语法和含义</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
<li><ol start="2">
<li>==Java虚拟机栈==<ul>
<li><ol>
<li>虚拟机栈描述的是JAVA方法执行的动态内存模型</li>
</ol>
</li>
<li><ol start="2">
<li>栈帧<ul>
<li><ol>
<li>每个方法执行,都会创建一个栈帧,伴随着方法从创建到执行完成。用于存储局部变量表,操作数栈,动态链接,方法出口等。</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
<li><ol start="3">
<li>局部变量表<ul>
<li><ol>
<li>存放编译器可知的各种基本数据类型,引用类型,returnAddress类型</li>
</ol>
</li>
<li><ol start="2">
<li>局部变量表的内存空间在编译期完成分配,当进入一个方法时,这个方法需要在帧分配多少内存是固定的,在方法运行期间是不会改变局部变量表的大小</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
<li><ol start="4">
<li>大小<ul>
<li><ol>
<li>StackOverflowError</li>
</ol>
</li>
<li><ol start="2">
<li>OutOfMemory</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
<li><ol start="3">
<li>本地方法栈<ul>
<li>两个栈的区别 <ul>
<li>虚拟机栈 ：  为虚拟机执行Java方法服务</li>
<li>本地方法栈 ：为虚拟机执行native方法服务</li>
</ul>
</li>
<li>其实这个Java虚拟机栈和本地方法栈没有多大的区别,异同都有;</li>
</ul>
</li>
</ol>
</li>
<li><ol start="4">
<li>堆内存(Java堆)<ul>
<li><ol>
<li>存储对象的实例</li>
</ol>
</li>
<li><ol start="2">
<li>垃圾收集器管理的主要区域</li>
</ol>
</li>
<li><ol start="3">
<li>新生代、老年代、Eden空间<br>(分出来这那么多块啊空间的主要是为了垃圾回收)</li>
</ol>
</li>
<li><ol start="4">
<li>OutOfMemory</li>
</ol>
</li>
<li><ol start="5">
<li>用 -Xmx -Xms 来指定内存大小</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
<li><ol start="5">
<li>方法区<ul>
<li><ol>
<li>存储虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据<ul>
<li><ol>
<li>类的信息：</li>
</ol>
<ul>
<li><ol>
<li>类的版本</li>
</ol>
</li>
<li><ol start="2">
<li>字段</li>
</ol>
</li>
<li><ol start="3">
<li>方法</li>
</ol>
</li>
<li><ol start="4">
<li>接口</li>
</ol>
</li>
</ul>
</li>
</ul>
</li>
</ol>
</li>
<li><ol start="2">
<li>方法区和永久代</li>
</ol>
</li>
<li><ol start="3">
<li>垃圾回收再方法区的行为</li>
</ol>
</li>
<li><ol start="4">
<li>异常的定义<ul>
<li><ol>
<li>OutOfMemoryError</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
<li><ol start="6">
<li>运行时常量池<ul>
<li><ol>
<li>属于方法区里面的一块</li>
</ol>
</li>
<li><ol start="2">
<li>eg:</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
</ul>
<pre><code>String s1 = &quot;abc&quot;;
String s2 = &quot;abc&quot;;
System.out.print( s1 == s2 );
// true
// 此处的&quot;abc&quot;称之为 字节码常量
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">graph LR</span><br><span class="line">s1--&gt;abc</span><br><span class="line">s2--&gt;abc</span><br></pre></td></tr></table></figure>
<ul>
<li style="list-style: none"><input type="checkbox" checked> 字符串并不是在 堆空间 中new(此处并没有new)出一个实例;而是在“常量池”里面创建(不是new)出来的,常量池里面对字符串来说有专门的一个空间叫做StringTable,在这个字符串表里面的数据结构是HashSet(无序且不重复),所以相同的字符串进来的时候只会有一个地址,所以不同的变量是引用的这同一个地址</li>
</ul>
<pre><code>String s3 = new String(&quot;abc&quot;);
System.out.print( s1 == s3 );
//false
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">graph LR</span><br><span class="line">s1--&gt;常量池创建出来的abc</span><br><span class="line">s3--&gt;堆空间中new出来的abc</span><br></pre></td></tr></table></figure>
<ul>
<li style="list-style: none"><input type="checkbox" checked> 此处为“new”,上面的s1,s2并没有new是在常量池;此处的new说明是在堆内存中开辟了一个”abc”的空间被栈中的s3引用;因为s3引用的”abc”是在堆空间中,而s1||s2引用的”abc”是在常量池中,这两者的内存区域都不同,所以为false</li>
</ul>
<pre><code>System.out.print( s1 == s3.intern());
//true
//此处的s3.intern();即经过intern()方法的&quot;abc&quot; 称之为 运行时常量
</code></pre><ul>
<li><p>[x] 为什么此处 s1 == s3.intern()  ??; intern()这个方法的作用是将 在堆内存中new出来的字符串 搬到 常量池中;那么此时的s1和s3.intern();就都在常量池中,因为字符串的内容相同那么在常量池里面的地址就是同一个地址,无序不重复;</p>
</li>
<li><ol start="7">
<li>直接内存<ul>
<li><ol>
<li>并不是运行时数据区的一部分;也不是java虚拟机规范的一块区域</li>
</ol>
</li>
<li><ol start="2">
<li>但是又确确实实的是一块内存区域而且还在被频繁的使用</li>
</ol>
</li>
<li><ol start="3">
<li>直接内存不会受到java虚拟机内存的制约</li>
</ol>
</li>
<li><ol start="4">
<li>但是会受到系统物理内存的制约</li>
</ol>
</li>
<li><ol start="5">
<li>主要是在JDK1.4开始的Nio里面直接分配内存</li>
</ol>
</li>
<li><ol start="6">
<li>基于通道与缓冲区什么东西的 new inputOut…来分配堆外内存<ul>
<li>下面这两句不知道哪句是真的:<ul>
<li><ol>
<li>(在这一块区域如果申请不到内存的话也会抛出OutOfMemory这个异常)</li>
</ol>
</li>
<li><ol start="2">
<li>(当出现OutOfMemory的时候就可以考虑这个直接内存的使用)</li>
</ol>
</li>
</ul>
</li>
</ul>
</li>
</ol>
</li>
<li>并 没 有 搞 懂 </li>
</ul>
</li>
</ol>
</li>
</ul>
<h4 id="10-对象的创建"><a href="#10-对象的创建" class="headerlink" title="10. 对象的创建"></a>10. 对象的创建</h4><hr>
<ul>
<li><p>10.1.1  给对象分配内存（概述与顺序）</p>
<ul>
<li><ol>
<li>线程安全性问题</li>
</ol>
</li>
<li><ol start="2">
<li>初始化对象</li>
</ol>
</li>
<li><ol start="3">
<li>执行构造方法</li>
</ol>
</li>
<li><ol start="4">
<li>顺序：<ul>
<li><ol>
<li>new 类名</li>
</ol>
</li>
<li><ol start="2">
<li>根据new的参数在常量池中定位一个类的符号引用</li>
</ol>
</li>
<li><ol start="3">
<li>如果没有找到这个符号引用,说明类还没有加载;则进行类的加载,解析和初始化</li>
</ol>
</li>
<li><ol start="4">
<li>虚拟机为对象分配内存 （位于堆中）</li>
</ol>
</li>
<li><ol start="5">
<li>将分配的内存初始化为零（不包括对象头）</li>
</ol>
</li>
<li><ol start="6">
<li>调用对象的<code>init();</code>方法</li>
</ol>
</li>
<li>中间的那 4个步骤 是在jvm里面执行对用户屏蔽了的</li>
</ul>
</li>
</ol>
</li>
</ul>
</li>
<li><p>10.1.2 给对象分配内存（操作方法）</p>
<ul>
<li><ol>
<li>方法一： 指针碰撞<ul>
<li><ol>
<li>(将一个长方体分成两块,左边为free右边为used,让右侧使用的内存越来越大的时候左侧自然会越来越小)</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
<li><ol start="2">
<li>方法二： 空间列表<ul>
<li><ol>
<li>(如果这个长方体的两侧已经发生混乱即两侧都有已经使用和未使用的内存这样不便于管理的时候,就会出现一个新的区域叫做空间列表;”空间列表”区域里面就会记载长方体左右两则的哪些空间是已经使用的哪些未被使用)</li>
</ol>
</li>
<li><ol start="2">
<li>指针碰撞 与 空间列表 具体在哪种情况下使用需要看”垃圾回收器”的情况</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
</ul>
</li>
<li><p>10.2 线程安全性问题：</p>
<ul>
<li><ol>
<li>解释：在”指针碰撞”方法中如果在高并发情况下同时多个使用多个多个释放,此时将此长方体一分为二的”分界指针”来不及移动就会造成数据错误;同样在空间列表方法中,在空间列表区域里面的记载的数据来不及更新瞬间的使用与释放就也会出问题。</li>
</ol>
</li>
<li><ol start="2">
<li>方法一：线程同步</li>
</ol>
</li>
<li><ol start="3">
<li>方法二：本地线程分配缓冲<ul>
<li><ol>
<li>(有多少个线程,就在即将要使用到空闲内存区域中分配几个单独的小区域,每个线程对应一个小区域这样就不会有相互干涉;如果线程所在的这个区域的内存已经满了那么就再来分配一个小区域供这个线程使用;这种方法解决了方法加锁在效率上的问题)</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
</ul>
</li>
<li>10.3 初始化对象</li>
<li>10.4 执行构造方法</li>
</ul>
<h5 id="11-探究-对象的结构"><a href="#11-探究-对象的结构" class="headerlink" title="11. 探究==对象的结构=="></a>11. 探究==对象的结构==</h5><hr>
<ul>
<li><ol>
<li>Header(对象头,对象的原数据)(这个是HotSpot虚拟机的对象头)<ul>
<li><ol>
<li>自身运行时数据(别名:Mark Word 根据32/64bit虚拟机的不同所占的大小来分为32/64位;将32位进行拆分,可能每几位就是一块,每一块都有不同的事做)<ul>
<li><ol>
<li>哈希值</li>
</ol>
</li>
<li><ol start="2">
<li>GC分代年龄</li>
</ol>
</li>
<li><ol start="3">
<li>锁状态标志</li>
</ol>
</li>
<li><ol start="4">
<li>线程持有的锁</li>
</ol>
</li>
<li><ol start="5">
<li>偏向线程ID</li>
</ol>
</li>
<li><ol start="6">
<li>偏向时间戳</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
<li><ol start="2">
<li>类型指针(对象指向他的类的原数据的指针)</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
<li><ol start="2">
<li>InstanceData(实例数据)()<ul>
<li><ol>
<li>分配都是按照宽度来分配区域;相同宽度的分配在同一个区域,比如下面这些：</li>
</ol>
</li>
<li><ol start="2">
<li>Longs doubles shorts/chars</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
<li><ol start="3">
<li>Padding(堆积填充)<ul>
<li><ol>
<li>这一部分的数据并不是一定就要存在,而是一定的占位符</li>
</ol>
</li>
<li><ol start="2">
<li>对象的字节必须是8个字节的整数倍</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
</ul>
<h5 id="12-深入理解对象的访问定位"><a href="#12-深入理解对象的访问定位" class="headerlink" title="12. 深入理解对象的访问定位"></a>12. 深入理解对象的访问定位</h5><hr>
<h6 id="对象对引用的两种方式：（HotSpot是第二种）"><a href="#对象对引用的两种方式：（HotSpot是第二种）" class="headerlink" title="对象对引用的两种方式：（HotSpot是第二种）"></a>对象对引用的两种方式：（HotSpot是第二种）</h6><ul>
<li><ul>
<li>方式一：使用句柄</li>
</ul>
</li>
<li><ul>
<li>方式二：直接指针</li>
</ul>
</li>
<li>上面指定的是两种方式从 栈内存 中做出一个引用指向到 堆内存中的 一块区域或者是对象本身(广义上讲这样的说法并不是很严谨)即：引用对象<ul>
<li><ol>
<li>如果是指向堆内存中的一块区域的话,这块区域被称为“句柄池”里面保存的就是 对象的地址信息等(这个区域在堆内存中名为句柄池,对象在堆内存中的实例池中)<ul>
<li><ol>
<li>问题：既然可以直接指向对象,为什么还要指向到句柄池再指向到对象?</li>
</ol>
</li>
<li><ol start="2">
<li>答： 栈内存中的地址是不会改变的,在改变的地址是堆内存中的地址,因为堆里面分配的内存可以到处跑或者被GC掉,那么这些会改变的地址都统一显示集中到句柄池里的话,这样栈指向堆的指针就不会野指</li>
</ol>
</li>
</ul>
</li>
</ol>
</li>
<li><ol start="2">
<li>直接使用指针的话：效率高,减少性能的开销(省去了句柄池这一环节)</li>
</ol>
</li>
</ul>
</li>
</ul>
<h3 id="13-垃圾回收"><a href="#13-垃圾回收" class="headerlink" title="13. 垃圾回收"></a>13. 垃圾回收</h3><hr>
<h5 id="13-1-概述"><a href="#13-1-概述" class="headerlink" title="13.1 概述"></a>13.1 概述</h5><h6 id="1-1-如何判定对象为垃圾对象"><a href="#1-1-如何判定对象为垃圾对象" class="headerlink" title="1.1 如何判定对象为垃圾对象"></a>1.1 如何判定对象为垃圾对象</h6><ul>
<li>引用计数法</li>
<li>可达性分析法<h6 id="1-2-如何回收"><a href="#1-2-如何回收" class="headerlink" title="1.2 如何回收"></a>1.2 如何回收</h6></li>
<li>回收的策略(共4种收集算法)<ul>
<li>标记-清除 算法</li>
<li>复制 算法</li>
<li>标记-整理-清除 算法</li>
<li>分代收集 算法</li>
</ul>
</li>
<li>垃圾回收器<ul>
<li>Serial</li>
<li>Parnew</li>
<li>Cms</li>
<li>G1<h6 id="1-3-何时回收"><a href="#1-3-何时回收" class="headerlink" title="1.3 何时回收"></a>1.3 何时回收</h6></li>
</ul>
</li>
</ul>
<h4 id="①-判断是否为垃圾"><a href="#①-判断是否为垃圾" class="headerlink" title="① 判断是否为垃圾"></a>① 判断是否为垃圾</h4><h5 id="13-2-判断对象是否存活算法-可达性分析法"><a href="#13-2-判断对象是否存活算法-可达性分析法" class="headerlink" title="13.2 判断对象是否存活算法-可达性分析法"></a>13.2 判断对象是否存活算法-可达性分析法</h5><ul>
<li style="list-style: none"><input type="checkbox" checked> 在上面1.1提到如何判定对象对垃圾对象中有个“引用计数法”事实上引用计数法很困难而且不严谨,而且可达性分析法会达到引用计数法达不到的效果<h6 id="2-1-可达性分析思路：GC-Root"><a href="#2-1-可达性分析思路：GC-Root" class="headerlink" title="- 2.1 可达性分析思路：GC Root:"></a>- 2.1 可达性分析思路：GC Root:</h6></li>
<li style="list-style: none"><input type="checkbox" checked> 在栈内存中有个区域里面是GC Root(GC根节点),会去指向(只是一条线或者一根指针)堆内存中的所有区域(这些区域包括new的对象的区域啊等各种各样开辟的内存的区域模块)相当于是串联电路,会将所有的区域串接起来,如果有没有被串接到的区域,那么这个区域就是一个垃圾区域会被等到GC来回收处理(这条 串联导线 称为”引用链”)</li>
</ul>
<h6 id="2-2-作为GC-Roots的对象"><a href="#2-2-作为GC-Roots的对象" class="headerlink" title="- 2.2 作为GC Roots的对象:"></a>- 2.2 作为GC Roots的对象:</h6><ul>
<li><ol>
<li>虚拟机栈</li>
</ol>
</li>
<li><ol start="2">
<li>方法区的类属性所引用的对象</li>
</ol>
</li>
<li><ol start="3">
<li>方法区中常量所引用的对象</li>
</ol>
</li>
<li><ol start="4">
<li>本地方法栈中引用的对象</li>
</ol>
</li>
<li>上面这些都可以作为”GC Root”的节点去向下遍历哪些区域能够被串联起来,哪些不能的就被作为垃圾处理</li>
</ul>
<h4 id="②-回收方法"><a href="#②-回收方法" class="headerlink" title="② 回收方法"></a>② 回收方法</h4><h5 id="13-3-标记-清除算法-——-垃圾回收常用算法之一"><a href="#13-3-标记-清除算法-——-垃圾回收常用算法之一" class="headerlink" title="13.3 标记-清除算法 —— 垃圾回收常用算法之一"></a>13.3 标记-清除算法 —— 垃圾回收常用算法之一</h5><ul>
<li style="list-style: none"><input type="checkbox" checked> “垃圾清除算法” 为 所有垃圾回收算法的基础</li>
</ul>
<h6 id="实施原理："><a href="#实施原理：" class="headerlink" title="实施原理："></a>实施原理：</h6><ul>
<li style="list-style: none"><input type="checkbox" checked> 原理:上面“可达性分析法”里面的GC Root的引用链串接不到的地方(区域等)就会被标记,然后就会被删除(具体怎么标记和怎么删除,没讲清除..)</li>
</ul>
<h6 id="缺点："><a href="#缺点：" class="headerlink" title="缺点："></a>缺点：</h6><ul>
<li>空间问题：<ul>
<li>在堆内存区域中会有无数个区域,并且在整个堆内存中分布较为散乱(比如各种大小和颜色的圈圈),GC将垃圾回收后内存被释放掉(比如同样大小只是没有了颜色的圈圈),那么这个区域依然会在原地而且还是逐个的单个的大小不一的空的区域,并不是一个完整的大的连续的空间;对堆内存空间来说有影响,对再次开辟内存空间来说也有影响</li>
</ul>
</li>
<li>效率问题：<ul>
<li>因为这些区域分布较为散乱(可能一堆有用的区域里的旁边只有一个区域被回收的区域),这个样子当GC回收完成后并不能完全确定是否是真的回收完了,那么此时GC Root还要来遍历一道,GC还要来回收一道;这样就增加了开销降低了效率</li>
</ul>
</li>
</ul>
<h5 id="13-4-复制算法-——-垃圾回收常用算法之二"><a href="#13-4-复制算法-——-垃圾回收常用算法之二" class="headerlink" title="13.4 复制算法 —— 垃圾回收常用算法之二"></a>13.4 复制算法 —— 垃圾回收常用算法之二</h5><h6 id="复制算法-解决了-标记-清楚算法的-两大缺点"><a href="#复制算法-解决了-标记-清楚算法的-两大缺点" class="headerlink" title="复制算法 解决了 标记-清楚算法的 两大缺点"></a>复制算法 解决了 标记-清楚算法的 两大缺点</h6><p>==回顾jvm的内存结构==：从大的方面讲主要有两大块(pic:运行时数据区):</p>
<ul>
<li>线程独享<ul>
<li>虚拟机栈(又分为两个区域)<ul>
<li>新生代(又分为3个区域)<ul>
<li>Eden (伊甸园)(只要是新创建的就会扔到这个地方来,并且GC一直来光顾回收垃圾)</li>
<li>Survivor(存活区,即在Eden里面没有被GC杀掉的)(Survivor是有两块区域)</li>
<li>Tenured Gen(比较稳定,养老级别但是还没退休到老年代)</li>
</ul>
</li>
<li>老年代</li>
</ul>
</li>
<li>本地方法栈</li>
<li>程序计数器</li>
</ul>
</li>
<li>被线程锁共享(又分为两大块)<ul>
<li>堆内存</li>
<li>方法区</li>
</ul>
</li>
</ul>
<h6 id="复制算法原理："><a href="#复制算法原理：" class="headerlink" title="复制算法原理："></a>复制算法原理：</h6><ul>
<li><p>[x] “复制算法”会将内存分为两个区域设为AB区域(AB均属于survivor区域);++第一次++开辟的空间全部都在A空间去开辟,当GC在A空间回收后,“复制算法”会将A空间里面的已经清除了的区域和本来就没有用到的区域复制到B内存区域,那么B内存区域就是一段连续的完整的有效空余区域,A区域已经清理干净;++第二次++来开辟空间的时候在B区域开辟内存区域同样的当GC回收完成后,“复制算法”会将B中的复制到A区域,类似这样循环</p>
</li>
<li><p>这样的话就引入了一个新的问题： </p>
</li>
<li>每次用的时候只是用了内存的一半,造成了内存区域的极大浪费</li>
<li>==那么解决方法：(或新生代内存模型 pic:新生代内存示例)==</li>
<li style="list-style: none"><input type="checkbox" checked> 1. 将内存分为3-4个区域,A区域Eden 80%、B区域Survivor 10%(不稳定存活区域)、C区域Survivor 10%(稳定存活区域)、D区域Tenured Gen 0%(这个区域为新生代里面的老年区域,暂定为0,当C存活区里的对象已经多次存活的话就存入到D老年区,再进行分配);</li>
<li style="list-style: none"><input type="checkbox" checked> 2. 新开辟的空间都在A-Eden(80%)区域中,当GC回收一次垃圾后,将存活的对象放入到B-Survivor(10%)中(B为不稳定存活区域);这样多来几次,B-Survivor(10%)里面会来更多的从Eden里面的存活对象,(GC还偶尔会去B存活区域里面再回收一道)那么在B-Survivor(10%)里面存活的对象已经这几次存活后会存放到C-Survivor(10%)中(C为稳定存活区域),同样的在C区域存活很久的会存放到D(老年区域不是老年代)区域里面;(如果C区域里面的对象装满了,10%不够了,此时就会启动一个内存分配模型,将其他地方的内存通过计算分配点过来(类似于银行贷款,信誉越高贷款越多,如果自己无力还款的话,银行就从担保人那里扣钱,即内存分配模型拿不到内存了就会从另外的区域分配点内存过来)(内存担保-额外的申请内存))</li>
</ul>
<p><img src="https://sxk.s3.didiyunapi.com/pic/jvm/3.jpg" alt="image"></p>
<h6 id="总结：实际解决方法与上面出现的内存浪费并没有太大的关系-只是将内存多分配几个区域或将存活区压缩一下内存而已-上面提到的复制算法的AB区域都是Survivor区域"><a href="#总结：实际解决方法与上面出现的内存浪费并没有太大的关系-只是将内存多分配几个区域或将存活区压缩一下内存而已-上面提到的复制算法的AB区域都是Survivor区域" class="headerlink" title="总结：实际解决方法与上面出现的内存浪费并没有太大的关系,只是将内存多分配几个区域或将存活区压缩一下内存而已;(上面提到的复制算法的AB区域都是Survivor区域)"></a>总结：实际解决方法与上面出现的内存浪费并没有太大的关系,只是将内存多分配几个区域或将存活区压缩一下内存而已;(上面提到的复制算法的AB区域都是Survivor区域)</h6><h5 id="13-5-标记整理算法和分代收集算法——垃圾回收常用算法之三、四"><a href="#13-5-标记整理算法和分代收集算法——垃圾回收常用算法之三、四" class="headerlink" title="13.5 标记整理算法和分代收集算法——垃圾回收常用算法之三、四"></a>13.5 标记整理算法和分代收集算法——垃圾回收常用算法之三、四</h5><h6 id="在-13-4-讲的是回收“新生代”里面的垃圾-此处讲的主要应用于回收“老年代”里面的垃圾-如果新生代里面的垃圾有很难回收的话也可以使用这个方法进行回收"><a href="#在-13-4-讲的是回收“新生代”里面的垃圾-此处讲的主要应用于回收“老年代”里面的垃圾-如果新生代里面的垃圾有很难回收的话也可以使用这个方法进行回收" class="headerlink" title="在 13.4 讲的是回收“新生代”里面的垃圾,此处讲的主要应用于回收“老年代”里面的垃圾(如果新生代里面的垃圾有很难回收的话也可以使用这个方法进行回收)"></a>在 13.4 讲的是回收“新生代”里面的垃圾,此处讲的主要应用于回收“老年代”里面的垃圾(如果新生代里面的垃圾有很难回收的话也可以使用这个方法进行回收)</h6><ul>
<li><p>5.1 标记-整理-收集</p>
</li>
<li><p>[x] 老年代里面垃圾很少,有90%以上的存活,这样GC去清理垃圾的时候效率很低,还会有大量的开销;那么此时会++将“老年代”内存区域分为两个AB两个区域++,①将需要清理的垃圾标记出来,②让稳定存活的到A区域去,需要清理的到B区域去,③GC收集;这样收集的时候GC只是回收了B区域而没有去管A区域就极大的提高了效率</p>
</li>
<li><p>5.2 分代收集算法(结合了标记整理算法和复制算法)<br>“分代收集算法”是根据 新生代 和 老年代 来进行选择垃圾回收算法的;比如：对于垃圾回收较高的采用“复制算法”进行大面积的回收;对于内存回收率较为低的或者是老年代就使用“标记-整理-收集”算法</p>
</li>
</ul>
<h4 id="③-垃圾收集器"><a href="#③-垃圾收集器" class="headerlink" title="③ 垃圾收集器"></a>③ 垃圾收集器</h4><h5 id="13-6-垃圾收集器——serial收集器"><a href="#13-6-垃圾收集器——serial收集器" class="headerlink" title="13.6 垃圾收集器——serial收集器"></a>13.6 垃圾收集器——serial收集器</h5><p>sun公司或者Oracle公司并没有对垃圾回收器做出一个统一的规范,所以每个公司都可以自定义自己的垃圾回收器</p>
<p>为什么垃圾回收器有那么多? —— 答： 根据不同的平台会有不同的垃圾回收器比如PC端移动端等,基本所有的设备都有垃圾回收器,有些可能在服务端和客户端也有不同的垃圾回收器</p>
<h6 id="serial收集器"><a href="#serial收集器" class="headerlink" title="- serial收集器"></a>- serial收集器</h6><ul>
<li>最基本，发展最悠久</li>
<li>单线程垃圾收集器(单开一个线程去回收垃圾)<ul>
<li><ol>
<li>感念：有多个线程在同时运行，此时垃圾回收器要来收集垃圾，就要让这“多个线程”暂停掉，让垃圾回收器的这“一个(单线程)”去执行垃圾回收;这样大大的降低了效率,程序执行一段时间就要停一段时间</li>
</ol>
</li>
<li><ol start="2">
<li>总结：单线程执行有好也有不好;如果是大线程的话那么效率就高;内存比较小的速度比较快的还是效率高比如桌面应用;对于上面讲的这个效率比较低在有些场合还是比较有用的</li>
</ol>
</li>
</ul>
</li>
<li>桌面应用</li>
<li>多用于 新生代内存 多用于 复制算法</li>
</ul>
<h5 id="13-7-垃圾收集器——parnew收集器"><a href="#13-7-垃圾收集器——parnew收集器" class="headerlink" title="13.7 垃圾收集器——parnew收集器"></a>13.7 垃圾收集器——parnew收集器</h5><ul>
<li>复制算法(新生代收集器)</li>
</ul>
<p>上面讲到的“serial收集器”是单个线程收集器;此处的“Parnew收集器”是多个线程的收集器;</p>
<ul>
<li>概念：与上面的“Serial收集器”类似,只是当垃圾回收器去回收的时候执行的线程停了后,垃圾回收器的“多个线程同时”去执行垃圾回收,就上面讲到的单个线程去执行垃圾回收强多了;大大的提升了效率,缩短了时间间隔</li>
<li>但是：在客户端环境下，“Parnew收集器”还是不如serial收集器的效率的</li>
</ul>
<h6 id="CMS"><a href="#CMS" class="headerlink" title="CMS"></a>CMS</h6><ul>
<li style="list-style: none"><input type="checkbox"> JDK1.5 后有个垃圾回收器叫做“CMS”,这款垃圾收集器真正做到了在++方法线程的执行过程中,垃圾回收的线程也能够同步执行++(即边扔垃圾边扫地)</li>
<li style="list-style: none"><input type="checkbox"> 如果CMS用于老年代的垃圾回收的话,那么新生代的垃圾回收必须要使用serial或者parnew这两个中的一个;CMS不能同时工作在新生代和老年代的两个分代空间中</li>
</ul>
<h5 id="13-8-垃圾收集器——parallel-Scavenge-收集器"><a href="#13-8-垃圾收集器——parallel-Scavenge-收集器" class="headerlink" title="13.8 垃圾收集器——parallel Scavenge 收集器"></a>13.8 垃圾收集器——parallel Scavenge 收集器</h5><ul>
<li>复制算法(新生代收集器)</li>
<li>多线程收集器</li>
<li>目标是：可以达到一定的吞吐量<ul>
<li><ol>
<li>吞吐量： CPU用于运行用户代码的时间 与 CPU消耗的总时间的比值</li>
</ol>
</li>
<li><ol start="2">
<li>吞吐量 = (执行用户代码时间) / (执行用户代码的时间 + 垃圾回收所占用的时间)</li>
</ol>
</li>
</ul>
</li>
</ul>
<pre><code>吞吐量 = (执行用户代码时间) / (执行用户代码的时间 + 垃圾回收所占用的时间)
</code></pre><ul>
<li>-XX:MaxGCPauseMillis 垃圾收集器最大停顿时间<ul>
<li>可以用户自定义指定,比如为1,那么就是1ms的时间去回收垃圾(可能并没有将垃圾回收完全,而且回收垃圾的频率就高了,这个需要根据项目具体需要去衡量)</li>
</ul>
</li>
<li>-XX:CGTimeRatio 吞吐量大小<ul>
<li>范围：(1,100)闭区间</li>
<li>比值： 1% - 99%<h6 id="parallel-Scavenge-与-parnew-的区别："><a href="#parallel-Scavenge-与-parnew-的区别：" class="headerlink" title="parallel Scavenge 与 parnew 的区别："></a>parallel Scavenge 与 parnew 的区别：</h6></li>
</ul>
</li>
<li>parallel Scavenge 可以指定行为参数,根据项目具体来设置达到一种优化效果</li>
</ul>
<h5 id="13-9-垃圾收集器-——-CMS-收集器"><a href="#13-9-垃圾收集器-——-CMS-收集器" class="headerlink" title="++13.9 垃圾收集器 —— CMS 收集器++"></a>++13.9 垃圾收集器 —— CMS 收集器++</h5><h6 id="CMS-Concurrent-Mark-Sweep-并发标记清除-收集器"><a href="#CMS-Concurrent-Mark-Sweep-并发标记清除-收集器" class="headerlink" title="CMS:Concurrent Mark Sweep ( 并发标记清除 收集器 )"></a>CMS:Concurrent Mark Sweep ( 并发标记清除 收集器 )</h6><p><img src="https://sxk.s3.didiyunapi.com/pic/jvm/4.jpg" alt="image"></p>
<ul>
<li>工作过程 (与前面的标记-清除算法一致;是老年代垃圾收集器)<ul>
<li>初始标记<ul>
<li><ol>
<li>引用计数法</li>
</ol>
</li>
<li><ol start="2">
<li>可达性分析法 (GCRoot向下遍历)</li>
</ol>
</li>
</ul>
</li>
<li>并发标记<ul>
<li><ol start="3">
<li>接着往下找</li>
</ol>
</li>
</ul>
</li>
<li>重新标记<ul>
<li><ol start="4">
<li>重新标记在初始和并发比较期间因程序运作而产生变动而没有处理好的对象(即对并发标记的修正)</li>
</ol>
</li>
</ul>
</li>
<li>并发清理<ul>
<li><ol start="5">
<li>修正完了过后开始清理垃圾</li>
</ol>
</li>
</ul>
</li>
</ul>
</li>
<li>优点<ul>
<li>并发收集</li>
<li>低停顿</li>
</ul>
</li>
<li>缺点<ul>
<li>占用大量的CPU资源(过程很长,还是并发的)</li>
<li>无法处理浮动垃圾(刚刚扫走后又重新扔的垃圾,只有等第二次来扫了)</li>
<li>出现Concurrent Mode Failure(在并发标记和并发清理同时运行的过程中,在并发清理过后重新并发标记的垃圾要扔到一个新的内存空间去,如果这个空间小了就会抛出这个错误如果这个空间大了就会浪费内存)</li>
<li>空间碎片 (标记-清除算法本来就会产生碎片)</li>
</ul>
</li>
</ul>
<p>CMS有这么多的缺点为什么还是要用它? 这里提到两个概念：并行/并发;并行：扫地与清理垃圾同时进行;并发：多个人同时清理垃圾同时仍垃圾;CMS在“标记”和“清理”阶段都非常的耗时间,在这两个阶段都是并行执行的</p>
<h5 id="13-10-最牛的垃圾收集器——-G1-收集器"><a href="#13-10-最牛的垃圾收集器——-G1-收集器" class="headerlink" title="13.10 最牛的垃圾收集器—— G1 收集器"></a>13.10 最牛的垃圾收集器—— G1 收集器</h5><h6 id="Garbage-First"><a href="#Garbage-First" class="headerlink" title="Garbage First"></a>Garbage First</h6><ul>
<li>历史<ul>
<li>2004年sun第一篇G1论文提出</li>
<li>2006年开始计划研制G1</li>
</ul>
</li>
<li>优势<ul>
<li>并行与并发</li>
<li>分代收集(不分新生代还是老年代 会分为无数个Region内存区域)</li>
<li>空间整合</li>
<li>可预测的停顿</li>
</ul>
</li>
<li>步骤<ul>
<li>初始标记(与CMS一致)</li>
<li>并发标记</li>
<li>最终标记(也是并发的)</li>
<li>筛选回收</li>
<li>此处涉及了一个表应用问题比较麻烦“Remember Set”</li>
</ul>
</li>
<li>与CMS相比</li>
</ul>
<h4 id="14-内存分配"><a href="#14-内存分配" class="headerlink" title="14. 内存分配"></a>14. 内存分配</h4><hr>
<h5 id="14-1-概述"><a href="#14-1-概述" class="headerlink" title="14.1 概述"></a>14.1 概述</h5><p>(自动内存管理)</p>
<p>1.1 几大原则：</p>
<ul>
<li>优先分配到Eden</li>
<li>大对象直接分配到老年代</li>
<li>长期存活的对象分配到老年代</li>
<li>空间分配担保(如果新生代的内存不够需要去老年代里面去借)</li>
<li>动态对象的年龄判断</li>
</ul>
<h5 id="14-2-Eden区域"><a href="#14-2-Eden区域" class="headerlink" title="14.2 Eden区域"></a>14.2 Eden区域</h5><h6 id="Eclipse里面打印出垃圾回收相关的信息设置："><a href="#Eclipse里面打印出垃圾回收相关的信息设置：" class="headerlink" title="Eclipse里面打印出垃圾回收相关的信息设置："></a>Eclipse里面打印出垃圾回收相关的信息设置：</h6><ul>
<li style="list-style: none"><input type="checkbox"> 右键运行配置里面“Arguments”中“VM arguments”设置“-verbose:gc -XX:+PrintGCDetails”<ul>
<li>在此输出中会显示当前运行代码的堆内存中的新生代是哪个垃圾收集器收集了什么垃圾,老年代垃圾收集器叫什么名字收集了哪些垃圾</li>
</ul>
</li>
<li style="list-style: none"><input type="checkbox"> 指定哪个收集器来收集垃圾：(同样跟上通用的虚拟机参数)-verbose:gc -XX:+PrintGCDetails -XX:+UseSerialGC</li>
<li style="list-style: none"><input type="checkbox"> 指定堆内存大小：-Xms20M -Xmx20M</li>
<li style="list-style: none"><input type="checkbox"> 指定新生代内存大小: -Xmn10M (新生代内存设置不好的话会严重影响内存)</li>
<li style="list-style: none"><input type="checkbox"> 新生代内存中Eden区域内存的指定： -XX:SurvivorRatio=8,那么此时两个存活区就各得到一份,Eden就得到8份</li>
<li style="list-style: none"><input type="checkbox" checked> 两种GC的区别：[GC (Allocation Failure)]: 不常用而且耗时是下面的10倍以上;[Full GC (System.gc())]: 常用</li>
</ul>
<h5 id="14-3-大对象直接进入老年代"><a href="#14-3-大对象直接进入老年代" class="headerlink" title="14.3 大对象直接进入老年代"></a>14.3 大对象直接进入老年代</h5><ul>
<li style="list-style: none"><input type="checkbox" checked> -XX:PretenureSizeThreshold</li>
<li><p>上面这个是指定一个数值,内存数值,如果对象的大小大于了这个数值就直接进入到老年代</p>
<pre><code>-verbose:gc -XX:+PrintGCDetails
-XX:+UseSerialGC -Xms20M -Xmn10M
-XX:SuriverRatio=8
-XX:PretenureSizeThreshold=6M
</code></pre></li>
<li><p>JDK8之前数值设为的是字节;JDK8开始可以设为M</p>
</li>
<li>默认值：&lt;=7M放在新生代;&gt;8M放在老年代</li>
</ul>
<h5 id="14-4-长期存活的对象进入老年代"><a href="#14-4-长期存活的对象进入老年代" class="headerlink" title="14.4 长期存活的对象进入老年代"></a>14.4 长期存活的对象进入老年代</h5><ul>
<li style="list-style: none"><input type="checkbox" checked> -XX:MaxTenuringThreshold  15</li>
<li>Age   1 + 1 + 1 </li>
</ul>
<h5 id="14-5-空间分配担保"><a href="#14-5-空间分配担保" class="headerlink" title="14.5 空间分配担保"></a>14.5 空间分配担保</h5><ul>
<li style="list-style: none"><input type="checkbox" checked> -XX:+HandlePromotionFailure</li>
<li>“+”为开启;”-“为禁用</li>
<li>当新生代内存不够的时候 会向老年代内存借;老年代内存会先衡量自身有没有那么多的内存给新生代借去满足新生代的内存需要,如果新生代需要的量 老年代给的出来的话 老年代就会给</li>
<li>当然还要满足其他什么条件,比如什么大于一个平均值啊……</li>
</ul>
<h5 id="14-6-逃逸分析与栈上分配"><a href="#14-6-逃逸分析与栈上分配" class="headerlink" title="14.6 逃逸分析与栈上分配"></a>14.6 逃逸分析与栈上分配</h5><ul>
<li>逃逸分析：分析对象的作用域</li>
</ul>
<h4 id="15-虚拟机工具"><a href="#15-虚拟机工具" class="headerlink" title="15 虚拟机工具"></a>15 虚拟机工具</h4><ul>
<li>Jps</li>
<li>Jstat</li>
<li>Jinfo</li>
<li>Jmap</li>
<li>Jhat</li>
<li>Jstack </li>
<li>jConsole</li>
</ul>
<h5 id="15-1-JPS"><a href="#15-1-JPS" class="headerlink" title="15.1 JPS"></a>15.1 JPS</h5><ul>
<li>JPS-&gt; Java Process status (类似于win的任务管理器)</li>
<li>本地虚拟机唯一id即lvmid: local virtual Machine id<ul>
<li>jps : 查看当前java的进程(即编号,这个编号类似于Linux的PID)</li>
<li>jps -m ：查看当前运行的Java程序的进程</li>
<li>jps -v : 查看jps的版本及jps环境信息</li>
<li>jps -mlv : 更加详细的查看java进程相关信息</li>
</ul>
</li>
<li>m :运行时传入主类的参数</li>
<li>v :虚拟机参数</li>
<li>l :运行的主类全名 或者 jar包名称</li>
</ul>
<h5 id="15-2-Jstat"><a href="#15-2-Jstat" class="headerlink" title="15.2 Jstat"></a>15.2 Jstat</h5><ul>
<li>类装载、内存、垃圾收集、jit编译的信息</li>
<li>用jps查看执行进程编号;在jstat -跟这个编号,就可以查出响应的信息</li>
<li>jstat -gcutil 再跟编号 就会看到一些参数的含义(垃圾回收的摘要信息,对这些信息进行监控);</li>
</ul>
<p><img src="https://sxk.s3.didiyunapi.com/pic/jvm/5.jpg" alt="image"></p>
<ul>
<li>动态监控：</li>
<li>jstat -gcutil 跟jps号 跟多长时间一次监控(ms) 跟监控多少次</li>
<li>eg:         jstat -gcutil 6692 1000 10 //每隔1s的时间监控一次这个进程,共监控10次</li>
<li>==元空间==的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于：元空间并不在虚拟机中,而是使用==本地内存==。因为,默认情况下,元空间的大小仅受本地内存限制</li>
<li>在JDK7包括以前是有永久代的,即“垃圾回收的摘要信息”里面有EOP,现在只有M了,M就是元空间</li>
</ul>
<h5 id="15-3-Jinfo"><a href="#15-3-Jinfo" class="headerlink" title="15.3 Jinfo"></a>15.3 Jinfo</h5><h6 id="实时查看和调整虚拟机的各项参数"><a href="#实时查看和调整虚拟机的各项参数" class="headerlink" title="实时查看和调整虚拟机的各项参数"></a>实时查看和调整虚拟机的各项参数</h6><h6 id="查看：-flag"><a href="#查看：-flag" class="headerlink" title="查看：  -flag "></a>查看：  -flag <name></name></h6><ul>
<li>如果打开了Eclipse,用jps可以看到它的PID进程号,那么jps -v 可以查看响应信息外还可以看到这个进程号使用了哪个垃圾收集器(此处看到的应该是G1即“ -XX:+UseG1GC”)</li>
<li>Jinfo的作用就是可以查看用了哪个虚拟机</li>
<li>Jinfo -flag  UseSerialGC PID   (查看这个PID是否使用了Serial垃圾收集器)<ul>
<li>如果是true:  -XX:+UseSerialGC</li>
<li>如果是false: -XX:-UseSerialGC</li>
</ul>
</li>
<li>Jinfo -flag UseG1GC pid (与上类似)<ul>
<li>“+”,“-” 表示是启用和不启用</li>
</ul>
</li>
</ul>
<p><img src="https://sxk.s3.didiyunapi.com/pic/jvm/6.jpg" alt="image"></p>
<h6 id="调整：-flag-启动或者禁用某个VM"><a href="#调整：-flag-启动或者禁用某个VM" class="headerlink" title="调整：- flag [+/-]  //启动或者禁用某个VM"></a>调整：- flag [+/-] <name> //启动或者禁用某个VM</name></h6><h6 id="调整：-flag-设置VM赋予一个什么值"><a href="#调整：-flag-设置VM赋予一个什么值" class="headerlink" title="调整：-flag  =  //设置VM赋予一个什么值"></a>调整：-flag <name> = <value> //设置VM赋予一个什么值</value></name></h6><h6 id="查看：-flags-打印虚拟机的参数"><a href="#查看：-flags-打印虚拟机的参数" class="headerlink" title="查看：-flags  打印虚拟机的参数"></a>查看：-flags  打印虚拟机的参数</h6><h6 id="查看：-sysprops-打印Java系统的配置变量"><a href="#查看：-sysprops-打印Java系统的配置变量" class="headerlink" title="查看：-sysprops 打印Java系统的配置变量"></a>查看：-sysprops 打印Java系统的配置变量</h6><h5 id="15-4-Jmap"><a href="#15-4-Jmap" class="headerlink" title="15.4 Jmap"></a>15.4 Jmap</h5><ul>
<li>Jmap 与 Jinfo 的用法差不多一致;</li>
<li><p>另外这些工具里面的命令不是每个命令都能使用;有些命令在Linux下才能使用会根据系统平台而定</p>
<pre><code>jmap -dump:format=b,file=c:\a.bin PID
</code></pre></li>
<li><p>上面这个命令是生成这个PID(Java进程)的快照;再用分析工具来分析下这个“a.bin”文件的内存啊堆栈啊垃圾回收啊之类的信息(导出堆栈信息)</p>
</li>
<li><p>之前是用的在Eclipse里面设置jvm参数来导出错误信息</p>
<pre><code>-XX:+HeapDumpOnOutOfMemoryErroe
</code></pre></li>
<li><p>jmap -histo PID  //是查看所有存活的什么的状态</p>
<ul>
<li>里面会看到 类的信息 和 实例的信息</li>
<li>如果查看到的信息很多的话,可以使用类似于Linux中的管道命令(下面这个是分页查询,通过管道命令将很多信息进行分页)<ul>
<li>eg： jmap -histo 8286 | more </li>
</ul>
</li>
</ul>
</li>
</ul>
<h5 id="15-5-Jhat"><a href="#15-5-Jhat" class="headerlink" title="15.5 Jhat"></a>15.5 Jhat</h5><h6 id="Jhat-JVM-heap-Analysis-Tool"><a href="#Jhat-JVM-heap-Analysis-Tool" class="headerlink" title="Jhat: JVM heap Analysis Tool"></a>Jhat: JVM heap Analysis Tool</h6>
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2018/03/12/redis/" rel="next" title="redis">
                <i class="fa fa-chevron-left"></i> redis
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2018/04/19/init/" rel="prev" title="Init">
                Init <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">S-Name Small·kk</p>
              <p class="site-description motion-element" itemprop="description">开源 | Java | 个人笔记 | 我的博客</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/">
              
                  <span class="site-state-item-count">12</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            

            

          </nav>

          

          

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#深入理解Java虚拟机-jvm性能调优-内存模型-虚拟机原理"><span class="nav-number">1.</span> <span class="nav-text">深入理解Java虚拟机(jvm性能调优+内存模型+虚拟机原理)</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#1-jdk-、jre-、jvm的关系"><span class="nav-number">1.0.0.1.</span> <span class="nav-text">1. jdk 、jre 、jvm的关系</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#2-内存溢出问题的分析与解决"><span class="nav-number">1.0.0.2.</span> <span class="nav-text">2. 内存溢出问题的分析与解决</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#3-jvm可视化监控工具"><span class="nav-number">1.0.0.3.</span> <span class="nav-text">3. jvm可视化监控工具</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#4-Java的发展历史"><span class="nav-number">1.0.0.3.1.</span> <span class="nav-text">4. Java的发展历史</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#5-Java技术体系"><span class="nav-number">1.0.0.3.2.</span> <span class="nav-text">5. Java技术体系</span></a></li></ol></li><li class="nav-item nav-level-5"><a class="nav-link" href="#6-Java8新特性"><span class="nav-number">1.0.0.4.</span> <span class="nav-text">6. Java8新特性</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#7-lanmbda表达式简介"><span class="nav-number">1.0.0.5.</span> <span class="nav-text">7. lanmbda表达式简介</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#8-Java虚拟机"><span class="nav-number">1.0.0.6.</span> <span class="nav-text">8. Java虚拟机</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#9-内存区域"><span class="nav-number">1.0.0.7.</span> <span class="nav-text">9. 内存区域</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#10-对象的创建"><span class="nav-number">1.0.1.</span> <span class="nav-text">10. 对象的创建</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#11-探究-对象的结构"><span class="nav-number">1.0.1.1.</span> <span class="nav-text">11. 探究==对象的结构==</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#12-深入理解对象的访问定位"><span class="nav-number">1.0.1.2.</span> <span class="nav-text">12. 深入理解对象的访问定位</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#对象对引用的两种方式：（HotSpot是第二种）"><span class="nav-number">1.0.1.2.1.</span> <span class="nav-text">对象对引用的两种方式：（HotSpot是第二种）</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#13-垃圾回收"><span class="nav-number">1.1.</span> <span class="nav-text">13. 垃圾回收</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#13-1-概述"><span class="nav-number">1.1.0.1.</span> <span class="nav-text">13.1 概述</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#1-1-如何判定对象为垃圾对象"><span class="nav-number">1.1.0.1.1.</span> <span class="nav-text">1.1 如何判定对象为垃圾对象</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#1-2-如何回收"><span class="nav-number">1.1.0.1.2.</span> <span class="nav-text">1.2 如何回收</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#1-3-何时回收"><span class="nav-number">1.1.0.1.3.</span> <span class="nav-text">1.3 何时回收</span></a></li></ol></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#①-判断是否为垃圾"><span class="nav-number">1.1.1.</span> <span class="nav-text">① 判断是否为垃圾</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#13-2-判断对象是否存活算法-可达性分析法"><span class="nav-number">1.1.1.1.</span> <span class="nav-text">13.2 判断对象是否存活算法-可达性分析法</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#2-1-可达性分析思路：GC-Root"><span class="nav-number">1.1.1.1.1.</span> <span class="nav-text">- 2.1 可达性分析思路：GC Root:</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#2-2-作为GC-Roots的对象"><span class="nav-number">1.1.1.1.2.</span> <span class="nav-text">- 2.2 作为GC Roots的对象:</span></a></li></ol></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#②-回收方法"><span class="nav-number">1.1.2.</span> <span class="nav-text">② 回收方法</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#13-3-标记-清除算法-——-垃圾回收常用算法之一"><span class="nav-number">1.1.2.1.</span> <span class="nav-text">13.3 标记-清除算法 —— 垃圾回收常用算法之一</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#实施原理："><span class="nav-number">1.1.2.1.1.</span> <span class="nav-text">实施原理：</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#缺点："><span class="nav-number">1.1.2.1.2.</span> <span class="nav-text">缺点：</span></a></li></ol></li><li class="nav-item nav-level-5"><a class="nav-link" href="#13-4-复制算法-——-垃圾回收常用算法之二"><span class="nav-number">1.1.2.2.</span> <span class="nav-text">13.4 复制算法 —— 垃圾回收常用算法之二</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#复制算法-解决了-标记-清楚算法的-两大缺点"><span class="nav-number">1.1.2.2.1.</span> <span class="nav-text">复制算法 解决了 标记-清楚算法的 两大缺点</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#复制算法原理："><span class="nav-number">1.1.2.2.2.</span> <span class="nav-text">复制算法原理：</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#总结：实际解决方法与上面出现的内存浪费并没有太大的关系-只是将内存多分配几个区域或将存活区压缩一下内存而已-上面提到的复制算法的AB区域都是Survivor区域"><span class="nav-number">1.1.2.2.3.</span> <span class="nav-text">总结：实际解决方法与上面出现的内存浪费并没有太大的关系,只是将内存多分配几个区域或将存活区压缩一下内存而已;(上面提到的复制算法的AB区域都是Survivor区域)</span></a></li></ol></li><li class="nav-item nav-level-5"><a class="nav-link" href="#13-5-标记整理算法和分代收集算法——垃圾回收常用算法之三、四"><span class="nav-number">1.1.2.3.</span> <span class="nav-text">13.5 标记整理算法和分代收集算法——垃圾回收常用算法之三、四</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#在-13-4-讲的是回收“新生代”里面的垃圾-此处讲的主要应用于回收“老年代”里面的垃圾-如果新生代里面的垃圾有很难回收的话也可以使用这个方法进行回收"><span class="nav-number">1.1.2.3.1.</span> <span class="nav-text">在 13.4 讲的是回收“新生代”里面的垃圾,此处讲的主要应用于回收“老年代”里面的垃圾(如果新生代里面的垃圾有很难回收的话也可以使用这个方法进行回收)</span></a></li></ol></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#③-垃圾收集器"><span class="nav-number">1.1.3.</span> <span class="nav-text">③ 垃圾收集器</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#13-6-垃圾收集器——serial收集器"><span class="nav-number">1.1.3.1.</span> <span class="nav-text">13.6 垃圾收集器——serial收集器</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#serial收集器"><span class="nav-number">1.1.3.1.1.</span> <span class="nav-text">- serial收集器</span></a></li></ol></li><li class="nav-item nav-level-5"><a class="nav-link" href="#13-7-垃圾收集器——parnew收集器"><span class="nav-number">1.1.3.2.</span> <span class="nav-text">13.7 垃圾收集器——parnew收集器</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#CMS"><span class="nav-number">1.1.3.2.1.</span> <span class="nav-text">CMS</span></a></li></ol></li><li class="nav-item nav-level-5"><a class="nav-link" href="#13-8-垃圾收集器——parallel-Scavenge-收集器"><span class="nav-number">1.1.3.3.</span> <span class="nav-text">13.8 垃圾收集器——parallel Scavenge 收集器</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#parallel-Scavenge-与-parnew-的区别："><span class="nav-number">1.1.3.3.1.</span> <span class="nav-text">parallel Scavenge 与 parnew 的区别：</span></a></li></ol></li><li class="nav-item nav-level-5"><a class="nav-link" href="#13-9-垃圾收集器-——-CMS-收集器"><span class="nav-number">1.1.3.4.</span> <span class="nav-text">++13.9 垃圾收集器 —— CMS 收集器++</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#CMS-Concurrent-Mark-Sweep-并发标记清除-收集器"><span class="nav-number">1.1.3.4.1.</span> <span class="nav-text">CMS:Concurrent Mark Sweep ( 并发标记清除 收集器 )</span></a></li></ol></li><li class="nav-item nav-level-5"><a class="nav-link" href="#13-10-最牛的垃圾收集器——-G1-收集器"><span class="nav-number">1.1.3.5.</span> <span class="nav-text">13.10 最牛的垃圾收集器—— G1 收集器</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#Garbage-First"><span class="nav-number">1.1.3.5.1.</span> <span class="nav-text">Garbage First</span></a></li></ol></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#14-内存分配"><span class="nav-number">1.1.4.</span> <span class="nav-text">14. 内存分配</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#14-1-概述"><span class="nav-number">1.1.4.1.</span> <span class="nav-text">14.1 概述</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#14-2-Eden区域"><span class="nav-number">1.1.4.2.</span> <span class="nav-text">14.2 Eden区域</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#Eclipse里面打印出垃圾回收相关的信息设置："><span class="nav-number">1.1.4.2.1.</span> <span class="nav-text">Eclipse里面打印出垃圾回收相关的信息设置：</span></a></li></ol></li><li class="nav-item nav-level-5"><a class="nav-link" href="#14-3-大对象直接进入老年代"><span class="nav-number">1.1.4.3.</span> <span class="nav-text">14.3 大对象直接进入老年代</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#14-4-长期存活的对象进入老年代"><span class="nav-number">1.1.4.4.</span> <span class="nav-text">14.4 长期存活的对象进入老年代</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#14-5-空间分配担保"><span class="nav-number">1.1.4.5.</span> <span class="nav-text">14.5 空间分配担保</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#14-6-逃逸分析与栈上分配"><span class="nav-number">1.1.4.6.</span> <span class="nav-text">14.6 逃逸分析与栈上分配</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#15-虚拟机工具"><span class="nav-number">1.1.5.</span> <span class="nav-text">15 虚拟机工具</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#15-1-JPS"><span class="nav-number">1.1.5.1.</span> <span class="nav-text">15.1 JPS</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#15-2-Jstat"><span class="nav-number">1.1.5.2.</span> <span class="nav-text">15.2 Jstat</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#15-3-Jinfo"><span class="nav-number">1.1.5.3.</span> <span class="nav-text">15.3 Jinfo</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#实时查看和调整虚拟机的各项参数"><span class="nav-number">1.1.5.3.1.</span> <span class="nav-text">实时查看和调整虚拟机的各项参数</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#查看：-flag"><span class="nav-number">1.1.5.3.2.</span> <span class="nav-text">查看：  -flag </span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#调整：-flag-启动或者禁用某个VM"><span class="nav-number">1.1.5.3.3.</span> <span class="nav-text">调整：- flag [+/-]  //启动或者禁用某个VM</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#调整：-flag-设置VM赋予一个什么值"><span class="nav-number">1.1.5.3.4.</span> <span class="nav-text">调整：-flag  =  //设置VM赋予一个什么值</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#查看：-flags-打印虚拟机的参数"><span class="nav-number">1.1.5.3.5.</span> <span class="nav-text">查看：-flags  打印虚拟机的参数</span></a></li><li class="nav-item nav-level-6"><a class="nav-link" href="#查看：-sysprops-打印Java系统的配置变量"><span class="nav-number">1.1.5.3.6.</span> <span class="nav-text">查看：-sysprops 打印Java系统的配置变量</span></a></li></ol></li><li class="nav-item nav-level-5"><a class="nav-link" href="#15-4-Jmap"><span class="nav-number">1.1.5.4.</span> <span class="nav-text">15.4 Jmap</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#15-5-Jhat"><span class="nav-number">1.1.5.5.</span> <span class="nav-text">15.5 Jhat</span></a><ol class="nav-child"><li class="nav-item nav-level-6"><a class="nav-link" href="#Jhat-JVM-heap-Analysis-Tool"><span class="nav-number">1.1.5.5.1.</span> <span class="nav-text">Jhat: JVM heap Analysis Tool</span></a></li></ol></li></ol></li></ol></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2018</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">S-Name Small·kk</span>

  
</div>


  <div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Pisces</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.4"></script>



  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  












  





  

  

  

  
  

  

  

  

</body>
</html>
